#include "sentinel.h"
#include "ui_sentinel.h"
#include "SpellEffect.h"
#include "Ability.h"
#include "Rotation.h"
#include "RatingConvert.h"
#include <fstream>

Sentinel::Sentinel(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Sentinel)
{
    ui->setupUi(this);
    updateStatBoxes();
}

Sentinel::~Sentinel()
{
    delete ui;
}

enum STATS {
    AIM = 0, CUNNING, STRENGTH, WILLPOWER = 3,
    CRIT, SURGE, ALACRITY , POWER , ACCURACY = 8,
    DEFENSE, SHIELD, ABSORB, ARMOR = 12,
    LEVEL, MH_ACC, OH_ACC, ENEMY_LEVEL, ENEMY_ARMOR= 17,
    SPEED,  MH_MAX, MH_MIN, OH_MAX , OH_MIN =22,
    TECH_CRIT_CHANCE , TECH_CRIT_SIZE, TECH_BONUS_HEALING, TECH_BONUS_DAMAGE = 26,
    RANGED_CRIT_CHANCE , RANGED_CRIT_SIZE, RANGED_BONUS_DAMAGE = 29,
    FORCE_CRIT_CHANCE , FORCE_CRIT_SIZE, FORCE_BONUS_HEALING, FORCE_BONUS_DAMAGE = 33,
    MELEE_CRIT_CHANCE , MELEE_CRIT_SIZE, MELEE_BONUS_DAMAGE = 36,
    TECH_POWER, FORCE_POWER = 38
};

//define global Sentinel variables
QString sentRotationOutput;
QString &sentRotationRef = sentRotationOutput;


//create a holder for the stats
std::vector <double> sentStats(39,0);



void Sentinel::setStats()
{
    int accBuff = 0;
    int critBuff = 3*(ui->skillBox_3->value());
    critBuff += 2*(ui->skillBox_2->value());
    if(ui->smugglerCheckBox->isChecked()) critBuff += 5;
    int forceSurgeBuff = 3*(ui->skillBox_4->value());
    //int aimUpgBuff = 3*(ui->skillBox_1->value());
    int alacBuff = 2*(ui->skillBox_6->value());
    if(ui->skillBox_5->value()==2) alacBuff += 5;

    int aim = ui->primaryBox->value();
    if(ui->consularCheckBox->isChecked()) aim *= 1.05;

    sentStats.at(STRENGTH) = aim;
    sentStats.at(WILLPOWER) = ui->secondaryBox->value();
    sentStats.at(CRIT)= ui->critBox->value();
    sentStats.at(SURGE)= ui->surgeBox->value();
    sentStats.at(POWER)= ui->powerBox->value();
    sentStats.at(FORCE_POWER) = ui->techBox->value();
    sentStats.at(ALACRITY)= ui->alacBox->value();
    sentStats.at(LEVEL)= ui->levelBox->value();

    sentStats.at(ACCURACY) = ui->accBox->value();
    sentStats.at(MH_MAX) = ui->MHmaxBox->value();
    sentStats.at(MH_MIN) = ui->MHminBox->value();
    sentStats.at(ENEMY_LEVEL) = ui->enemyLevelBox->value();
    sentStats.at(ENEMY_ARMOR) = ui->enemyArmorBox->value();

    sentStats.at(FORCE_CRIT_CHANCE) = ( ForceCritChance(sentStats, critBuff, true));
    sentStats.at(FORCE_CRIT_SIZE) = ( ForceCritSize(sentStats, forceSurgeBuff));
    sentStats.at(SPEED) =( Speed(sentStats, alacBuff));
    sentStats.at(MH_ACC) = (MH_Accuracy(sentStats, accBuff));
    sentStats.at(OH_ACC) = (OH_Accuracy(sentStats, accBuff));
    sentStats.at(FORCE_BONUS_DAMAGE) = ForceBonusDamage(sentStats, true);
    sentStats.at(MELEE_CRIT_CHANCE) = ( MeleeCritChance(sentStats, critBuff, false));
    sentStats.at(MELEE_CRIT_SIZE) = ( MeleeCritSize(sentStats, 0));
    sentStats.at(MELEE_BONUS_DAMAGE) = MeleeBonusDamage(sentStats, false);

}

vector <double> Sentinel::calculateStats(vector <double> &stats2){
    int accBuff = 0;
    int critBuff = 3*(ui->skillBox_3->value());
    critBuff += 2*(ui->skillBox_2->value());
    if(ui->smugglerCheckBox->isChecked()) critBuff += 5;
    int techSurgeBuff = 3*(ui->skillBox_4->value());
    int rangedSurgeBuff = 0;
    //int aimUpgBuff = 3*(ui->skillBox_1->value());
    int alacBuff = 2*(ui->skillBox_6->value());
    if(ui->skillBox_5->value()==2) alacBuff += 5;

    stats2.at(FORCE_CRIT_CHANCE) = ( ForceCritChance(stats2, critBuff, true));
    stats2.at(FORCE_CRIT_SIZE) = ( ForceCritSize(stats2, techSurgeBuff));
    stats2.at(SPEED) =( Speed(stats2, alacBuff));
    stats2.at(MH_ACC) = (MH_Accuracy(stats2, accBuff));
    stats2.at(OH_ACC) = (OH_Accuracy(stats2, accBuff));
    stats2.at(FORCE_BONUS_DAMAGE) = ForceBonusDamage(stats2, false);
    stats2.at(MELEE_CRIT_CHANCE) = ( MeleeCritChance(stats2, critBuff, false));
    stats2.at(MELEE_CRIT_SIZE) = ( MeleeCritSize(stats2, rangedSurgeBuff));
    stats2.at(MELEE_BONUS_DAMAGE) = MeleeBonusDamage(stats2, false);
    return stats2;
}

void Sentinel::computeAlacrity(){
    ui->castView->clear();
    ui->countView->clear();
    setStats();
    vector <double> stats2=sentStats;
    QString alacOutput = "Haste%, RSh SCG casts, RSh Casts, SCG usages, HSc+RSc casts, HSc+RSc SCG casts, Total Casts, HPS\n\n";
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();
    double HPS;
    for(double m=0.0;m<39.5;m+=0.5){
        stats2.at(SPEED)=1-(m/100);
        if(ui->fixedTimeButton->isChecked()){
        //HPS = bodyguardRotation(rotationTime,stats2);
        }else{
        //    HPS = bodyguardRotation(numCasts,stats2);
        }
//        alacOutput += QString::number(m) +" , " + QString::number(RSh_SCG_count) +" ,  " + QString::number(RSh_count)
//                +" , " + QString::number(SCG_count)+" , " + QString::number(RSc_count+HSc_count)
//                + " , " + QString::number(RSc_SCG_count + HSc_SCG_count)+ " , " + QString::number(RSc_count + HSc_count+ES_count + RSh_count)
//                +" , " + QString::number(HPS) +"\n";
    }
    ui->countView->insertPlainText(alacOutput);
}

void Sentinel::updateStatBoxes()
{

    setStats();
    ui->forceCritChanceLabel->setText(QString::number(sentStats.at(FORCE_CRIT_CHANCE)));
    ui->forceCritSizeLabel->setText(QString::number(sentStats.at(FORCE_CRIT_SIZE)));
    ui->meleeCritChanceLabel->setText(QString::number(sentStats.at(MELEE_CRIT_CHANCE)));
    ui->meleeCritSizeLabel->setText(QString::number(sentStats.at(MELEE_CRIT_SIZE)));
    ui->speedLabel->setText(QString::number(100*(1-sentStats.at(SPEED))));
    ui->MHaccLabel->setText(QString::number(sentStats.at(MH_ACC)));
    ui->OHaccLabel->setText(QString::number(sentStats.at(OH_ACC)));
    ui->forceBonusDamageLabel->setText(QString::number(sentStats.at(FORCE_BONUS_DAMAGE)));
    ui->meleeBonusDamageLabel->setText(QString::number(sentStats.at(MELEE_BONUS_DAMAGE)));

    if(ui->tree1->isChecked()){
        ui->accBox->setEnabled(false);
        ui->accBox_2->setEnabled(false);
        ui->accBox_3->setEnabled(false);
        ui->accuracyButton->setEnabled(false);
        ui->accLabel->setEnabled(false);
        ui->accLabel_2->setEnabled(false);
        ui->accLabel_3->setEnabled(false);
        ui->accWeightLabel->setEnabled(false);
        ui->MHaccLabel->setEnabled(false);
        ui->MHmaxBox->setEnabled(false);
        ui->MHmaxLabel->setEnabled(false);
        ui->MHminBox->setEnabled(false);
        ui->MHminLabel->setEnabled(false);
        ui->OHmaxBox->setEnabled(false);
        ui->OHmaxLabel->setEnabled(false);
        ui->OHminBox->setEnabled(false);
        ui->OHminLabel->setEnabled(false);
        ui->enemyArmorBox->setEnabled(false);
        ui->enemyArmorLabel->setEnabled(false);
        ui->enemyLevelBox->setEnabled(false);
        ui->enemyLevelLabel->setEnabled(false);
        ui->OHaccLabel->setEnabled(false);
    }
}

double Sentinel::calculateHPS(){
    double HPS = 0;
    setStats();
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();
    if(ui->fixedTimeButton->isChecked()){
     //   HPS = bodyguardRotation(rotationTime, sentStats);
    }else{
    //    HPS = bodyguardRotation(numCasts, sentStats);
    }

    return HPS;
}

double Sentinel::calculateDPS(){

}

void Sentinel::getWeights(){
    //copy stats for modification
    setStats();
    vector <double> stats2 = sentStats;
    double baseHPS, aimHPS, cunningHPS, powerHPS, critHPS, surgeHPS, alacHPS =0, refStat=1;

    double statBuff = 1+0.03*(ui->skillBox_1->value());
    std::vector <double> weights(8,0);
    for(int m=0;m<7;m++){
        stats2 = sentStats;
        switch(m){
        case 0:
            break;
        case 1:
            stats2.at(STRENGTH)+= (1*statBuff);
            break;
        case 2:
            stats2.at(POWER)+=1;
            break;
        case 3:
            stats2.at(CRIT)+=1;
            break;
        case 4:
            stats2.at(SURGE)+=1;
            break;
        case 5:
            stats2.at(ALACRITY)+=1;
            break;
        case 6:
            stats2.at(WILLPOWER)+=1;
            break;
        default:
            break;
        }
        stats2 = calculateStats(stats2);
        if(ui->fixedTimeButton->isChecked()){
            double numCasts = ui->numCasts->value();
         //   weights.at(m)=bodyguardRotation(numCasts, stats2);
        }else{
            int numCasts = ui->numCasts->value();
         //   weights.at(m)=bodyguardRotation(numCasts, stats2);
        }

    }
    baseHPS = weights.at(0);
    aimHPS = weights.at(1) -baseHPS;
    powerHPS = weights.at(2) -baseHPS;
    critHPS = weights.at(3) -baseHPS;
    surgeHPS = weights.at(4) -baseHPS;
    alacHPS = weights.at(5) -baseHPS;
    cunningHPS = weights.at(6) -baseHPS;

    if(ui->powerButton->isChecked())refStat = powerHPS;
    if(ui->aimButton->isChecked())refStat = aimHPS;
    if(ui->critButton->isChecked())refStat = critHPS;
    if(ui->surgeButton->isChecked())refStat = surgeHPS;
    if(ui->alacrityButton->isChecked())refStat = alacHPS;
    //if(ui->accuracyButton->isChecked())refStat = accuracyDPS;

    double powerWeight = powerHPS/refStat;
    double aimWeight = aimHPS/refStat;
    double cunningWeight = cunningHPS/refStat;
    double critWeight = critHPS/refStat;
    double surgeWeight = surgeHPS/refStat;
    double alacWeight = alacHPS/refStat;

    ui->critWeightLabel->setText(QString::number(critWeight));
    ui->surgeWeightLabel->setText(QString::number(surgeWeight));
    ui->alacWeightLabel->setText(QString::number(alacWeight));
    ui->powerWeightLabel->setText(QString::number(powerWeight));
    ui->primaryWeightLabel->setText(QString::number(aimWeight));
    ui->secondaryWeightLabel->setText(QString::number(cunningWeight));
}

void Sentinel::compareUpgrades(){
    setStats();
    vector <double> stats1 = sentStats;
    vector <double> stats2 = sentStats;
    double baseHPS = 0, upg1HPS = 1, upg2HPS = 2;
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();

    double statBuff = 1 + 0.03*(ui->skillBox_1->value());
    if(ui->consularCheckBox->isChecked()) statBuff += 0.05;

    if(ui->fixedTimeButton->isChecked()){
     //   baseHPS = bodyguardRotation(rotationTime, sentStats);
    }else{
     //   baseHPS = bodyguardRotation(numCasts, sentStats);
    }
    //populate upgrade 1
    stats1.at(STRENGTH) += (ui->primaryBox_2->value())*statBuff;
    stats1.at(WILLPOWER) += ui->secondaryBox_2->value();
    stats1.at(CRIT) += ui->critBox_2->value();
    stats1.at(SURGE) += ui->surgeBox_2->value();
    stats1.at(POWER) += ui->powerBox_2->value() + ui->techBox_2->value();
    stats1.at(ALACRITY) += ui->alacBox_2->value();

    stats1 = calculateStats(stats1);

    if(ui->fixedTimeButton->isChecked()){
     //   upg1HPS = bodyguardRotation(rotationTime, stats1);
    }else{
     //   upg1HPS = bodyguardRotation(numCasts, stats1);
    }

    //populate upgrade 2
    stats2.at(STRENGTH) += (ui->primaryBox_3->value())*statBuff;
    stats2.at(WILLPOWER) += ui->secondaryBox_3->value();
    stats2.at(CRIT) += ui->critBox_3->value();
    stats2.at(SURGE) += ui->surgeBox_3->value();
    stats2.at(POWER) += ui->powerBox_3->value() + ui->techBox_2->value();
    stats2.at(ALACRITY) += ui->alacBox_3->value();

    stats2 = calculateStats(stats2);
    if(ui->fixedTimeButton->isChecked()){
     //   upg2HPS = bodyguardRotation(rotationTime, stats2);
    }else{
     //   upg2HPS = bodyguardRotation(numCasts, stats2);
    }

    upg1HPS -= baseHPS;
    upg2HPS -= baseHPS;

    ui->HPSlabel_2->setText(QString::number(upg1HPS));
    ui->HPSlabel_3->setText(QString::number(upg2HPS));

    if(upg1HPS == upg2HPS) ui->upg3Label->setText("No difference");
    if(upg1HPS > upg2HPS) ui->upg3Label->setText("Use Item 1");
    if(upg1HPS < upg2HPS) ui->upg3Label->setText("Use Item 2");
}

void Sentinel::on_calcHPSButton_clicked()
{
updateStatBoxes();
//    double HPS = calculateHPS();
//    ui->castView->clear();
//    ui->countView->clear();
//    QString countString = "RSc casts: " + QString::number(RSc_count)+"\nHSc casts: " + QString::number(HSc_count)
//            +"\nRSh casts: " + QString::number(RSh_count)+ "\nRSc casts in SCG: " + QString::number(RSc_SCG_count)
//            +"\nHSc casts in SCC: " + QString::number(HSc_SCG_count) +"\nRSh casts in SCG: " + QString::number(RSh_SCG_count)
//            +"\nES casts: " + QString::number(ES_count) +"\nSCG usages: " + QString::number(SCG_count)
//            +"\nVH usages: " + QString::number(VH_count);
//    ui->countView->insertPlainText(countString);
//    ui->castView->insertPlainText(sentRotationOutput);
//    ui->HPSlabel->setText(QString::number(HPS));
}

void Sentinel::on_primaryBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_powerBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_critBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_alacBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_levelBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_secondaryBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_techBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_surgeBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_accBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_MHmaxBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_MHminBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_enemyLevelBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_enemyArmorBox_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_calcWeightButton_clicked()
{
    updateStatBoxes();
    getWeights();
}

void Sentinel::on_upgradeButton_clicked()
{
    compareUpgrades();
}

void Sentinel::on_check4pcBox_toggled(bool checked)
{
    if(checked==true) ui->check2pcBox->setChecked(true);
}

void Sentinel::on_check2pcBox_toggled(bool checked)
{
    if(checked==false) ui->check4pcBox->setChecked(false);
}


void Sentinel::on_computeAlacrityButton_clicked()
{
    computeAlacrity();
}

void Sentinel::on_skillBox_1_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_2_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_3_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_4_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_5_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_6_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_7_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_8_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_skillBox_9_editingFinished()
{
    updateStatBoxes();
}

void Sentinel::on_note1_clicked()
{
    ui->countView->clear();
    QString note1 = "*Note that Crit Size may differ from the value in game because Warden only affects heals, so does not show up on the in-game tooltip.";
    ui->countView->insertPlainText(note1);
}

void Sentinel::on_note2_clicked()
{
    ui->countView->clear();
    QString note2 = "**Note 2: Alacrity has complex interactions with SCG windows, resource mechanics, Effective Cost of abilities, etc.\n\n Current recommendation is for 5-7.5% Alacrity, not to exceed 8.5% for Commandos or 12.5% for Mercs. The difference is due to imbalance in their resource regen windows.  While Alacrity is not good for Mercs, it is especially bad for Commandos.\n\n For more information, see the following two threads on the SWTOR.com forums\n\n http://www.swtor.com/community/showthread.php?p=2900243#post2900243\n\nhttp://www.swtor.com/community/showthread.php?t=306667";
    ui->countView->insertPlainText(note2);
}

void Sentinel::on_saveStats_clicked()
{
    setStats();
    string filename = "Sentinel_stats.txt";
    ofstream fout (filename.c_str());
    fout << sentStats.at(STRENGTH) << "\n" << sentStats.at(WILLPOWER) << "\n" << sentStats.at(CRIT)<< "\n" <<
            sentStats.at(SURGE) << "\n" << ui->powerBox->value() << "\n" << ui->techBox->value() << "\n" << sentStats.at(ALACRITY) << "\n" <<
    sentStats.at(LEVEL) << "\n" << sentStats.at(ACCURACY) << "\n" << sentStats.at(MH_MAX) << "\n" <<
    sentStats.at(MH_MIN) << "\n" << sentStats.at(ENEMY_LEVEL) << "\n" << sentStats.at(ENEMY_ARMOR) << endl;

    fout << ui->skillBox_1->value() << "\n" << ui->skillBox_2->value() << "\n" << ui->skillBox_3->value() << "\n" <<
            ui->skillBox_4->value() << "\n" << ui->skillBox_5->value() << "\n" << ui->skillBox_6->value() << "\n" <<
            ui->skillBox_7->value() << "\n" << ui->skillBox_8->value() << "\n" << ui->skillBox_9->value() << "\n" << endl;

    fout << sentStats.at(OH_MAX) << "\n" << sentStats.at(OH_MIN) << endl;
    fout.close();
}

void Sentinel::on_loadStats_clicked()
{
    Load_Stats();
}

void Sentinel::Load_Stats(){
    string filename = "Sentinel_stats.txt";
    ifstream fin (filename.c_str());
    vector <string> inputStats(27,"0");
    int i=0;
    while(fin.good()){
        getline(fin,inputStats.at(i));
                i++;
    }
    ui->primaryBox->setValue(atoi(inputStats.at(0).c_str()));
    ui->secondaryBox->setValue(atoi(inputStats.at(1).c_str()));
    ui->critBox->setValue(atoi(inputStats.at(2).c_str()));
    ui->surgeBox->setValue(atoi(inputStats.at(3).c_str()));
    ui->powerBox->setValue(atoi(inputStats.at(4).c_str()));
    ui->techBox->setValue(atoi(inputStats.at(5).c_str()));
    ui->alacBox->setValue(atoi(inputStats.at(6).c_str()));
    ui->levelBox->setValue(atoi(inputStats.at(7).c_str()));
    ui->accBox->setValue(atoi(inputStats.at(8).c_str()));
    ui->MHmaxBox->setValue(atoi(inputStats.at(9).c_str()));
    ui->MHminBox->setValue(atoi(inputStats.at(10).c_str()));
    ui->enemyLevelBox->setValue(atoi(inputStats.at(11).c_str()));
    ui->enemyArmorBox->setValue(atoi(inputStats.at(12).c_str()));

//set skill boxes
    ui->skillBox_1->setValue(atoi(inputStats.at(13).c_str()));
    ui->skillBox_2->setValue(atoi(inputStats.at(14).c_str()));
    ui->skillBox_3->setValue(atoi(inputStats.at(15).c_str()));
    ui->skillBox_4->setValue(atoi(inputStats.at(16).c_str()));
    ui->skillBox_5->setValue(atoi(inputStats.at(17).c_str()));
    ui->skillBox_6->setValue(atoi(inputStats.at(18).c_str()));
    ui->skillBox_7->setValue(atoi(inputStats.at(19).c_str()));
    ui->skillBox_8->setValue(atoi(inputStats.at(20).c_str()));
    ui->skillBox_9->setValue(atoi(inputStats.at(21).c_str()));

    //Off-hand stats
    ui->OHmaxBox->setValue(atoi(inputStats.at(22).c_str()));
    ui->OHminBox->setValue(atoi(inputStats.at(23).c_str()));

    fin.close();
}

void Sentinel::on_tree1_clicked()
{
    updateStatBoxes();
}

void Sentinel::on_tree2_clicked()
{
    updateStatBoxes();
}

void Sentinel::on_tree3_clicked()
{
    updateStatBoxes();
}
